package com.nervenets.template.service.impl;

import com.nervenets.general.Global;
import com.nervenets.general.exception.LogicException;
import com.nervenets.general.jwt.util.JwtUtils;
import com.nervenets.general.model.GlobalSecurity;
import com.nervenets.general.model.MenuRole;
import com.nervenets.general.model.SecurityUser;
import com.nervenets.general.service.GlobalSecurityService;
import com.nervenets.template.hibernate.dao.RoleGroupDao;
import com.nervenets.template.hibernate.domain.user.RoleGroup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 2020/6/28 13:54 created by Joe
 **/
@Slf4j
@com.alibaba.dubbo.config.annotation.Service(version = "1.0.0")
@org.springframework.stereotype.Service
public class GlobalSecurityServiceImpl implements GlobalSecurityService {
    @Resource
    private RoleGroupDao roleGroupDao;

    @Override
    public SecurityUser getUserInfo(String token, String license, boolean encrypt) {
        return JwtUtils.getUser(token, license, encrypt);
    }

    @Override
    public String getToken(SecurityUser securityUser, String license) {
        return JwtUtils.getToken(securityUser, license);
    }

    @Override
    public void clearToken(long userId) {
        JwtUtils.clearToken(userId);
    }

    @Override
    public void authorize(String token, String license) {
        JwtUtils.authorize(token, license);
    }

    @Override
    public void logout(String token, String license) {
        JwtUtils.logout(token, license);
    }

    @Override
    @Cacheable(cacheNames = Global.Constants.GLOBAL_SECURITY_KEY, key = "#roleIds", sync = true)
    public GlobalSecurity getGlobalSecurity(List<Long> roleIds) {
        if (null == roleIds || roleIds.isEmpty()) throw new LogicException("权限组为空");
        final List<RoleGroup> roleGroups = roleGroupDao.findAllById(roleIds);
        final List<MenuRole> allMenuRoles = JwtUtils.getAllMenuRoles();

        Set<String> roles = new HashSet<>();
        Set<String> permissions = new HashSet<>();
        Set<String> interfaces = new HashSet<>();

        for (RoleGroup roleGroup : roleGroups) {
            for (MenuRole role : allMenuRoles) {
                List<String> allMenuIds = role.getAllMenuIds();
                if (roleGroup.getRoles().stream().anyMatch(allMenuIds::contains)) {
                    roles.add(role.getCode());
                    permissions.addAll(analysisActions(role, role.getCode(), roleGroup.getRoles(), roles, true));
                }
            }
            interfaces.addAll(roleGroup.getInterfaces());
        }
        return GlobalSecurity.builder()
                .menus(roles)
                .permissions(permissions)
                .interfaces(interfaces)
                .build();
    }

    private List<String> analysisActions(MenuRole menu, String prefix, List<String> roleIds, Set<String> menus, boolean menuAdd) {
        List<String> actions = new ArrayList<>();
        if (null != menu.getChildren()) {
            menu.getChildren().forEach(action -> {
                List<String> allMenuIds = action.getAllMenuIds();
                if (roleIds.stream().anyMatch(allMenuIds::contains)) {
                    if (menuAdd) menus.add(action.getCode());
                    List<String> a = new ArrayList<>();
                    a.add(prefix);
                    a.add(action.getCode());
                    final String newPrefix = String.join(":", a);
                    actions.add(newPrefix);
                    actions.addAll(analysisActions(action, newPrefix, roleIds, menus, false));
                }
            });
        }
        return actions;
    }
}
